package cc.spider.web.processor;


import cc.spider.core.IDataProcessor;
import cc.spider.model.FlowData;
import cc.spider.model.ResultInfo;
import cc.spider.model.TaskInfo;
import cc.spider.web.WebSpiderConfig;
import cc.spider.web.WebSpiderExtConfig;
import cc.spider.web.config.Config;
import cc.spider.web.config.DataRule;
import cc.spider.web.config.LinkRule;
import cc.spider.web.config.Task;
import cc.spider.web.model.http.RequestExt;
import cc.spider.web.parser.*;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 增强型的数据解析类
 */
public class UnifiedDataProcessor implements IDataProcessor {

    @Override
    public void process(FlowData flowData) {
        TaskInfo taskInfo = flowData.getTaskInfo();
        if (taskInfo instanceof RequestExt) {
            RequestExt request = (RequestExt) taskInfo;
            String taskName = request.getTaskName();
            Task task = Config.SPIDER_TASKS.get(taskName);
            HashMap<String, DataRule> dataRuleMap = task.getDataRule();
            ResultInfo<String> resultInfo = flowData.getResultInfo();
            ISelector selector = new JsoupParser(resultInfo.getResult(), request.getUrl());
            try {
                flowData.setFields(this.parseData(dataRuleMap, selector));
                this.parseLinks(flowData, task.getLinkRule(), selector);
                if (StringUtils.isNotEmpty(task.getNextTask())) {
                    flowData.addNextTaskInfo(Config.newTask(task.getNextTask()));
                }
            } catch (Exception e) {
                System.err.println(request.getUrl());
                e.printStackTrace();
            }
        }
    }

    private Map<String, Object> parseData(HashMap<String, DataRule> dataRuleMap, ISelector<IElement, IElements> parser) {
        Map<String, Object> map = new HashMap<>();
        for (String ruleKey : dataRuleMap.keySet()) {
            DataRule rule = dataRuleMap.get(ruleKey);
            String selector = rule.getRule();
            IHTMLParser htmlParser;
            if (rule.isArray()) {
                htmlParser = parser.queryAll(selector);
                if (rule.getFromIndex() < rule.getToIndex()) {
                    htmlParser = (IHTMLParser) ((IElements) htmlParser).sub(rule.getFromIndex(), rule.getToIndex());
                }
            } else {
                htmlParser = parser.query(selector);
            }
            if (!StringUtils.isEmpty(rule.getMethod())) {
                try {
                    Method method = htmlParser.getClass().getMethod(rule.getMethod());
                    Object result = method.invoke(htmlParser);
                    map.put(rule.getTitle(), result);
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            } else {
                map.put(rule.getTitle(), htmlParser.text());
            }
        }
        return map;
    }

    private void parseLinks(FlowData flowData, List<LinkRule> linkRuleList, ISelector<IElement, IElements> parser) {
        for (LinkRule rule : linkRuleList) {
            String selector = rule.getRule();
            IHTMLParser htmlParser;
            if (rule.isArray()) {
                htmlParser = parser.queryAll(selector);
                if (rule.getFromIndex() < rule.getToIndex()) {
                    htmlParser = (IHTMLParser) ((IElements) htmlParser).sub(rule.getFromIndex(), rule.getToIndex());
                }
            } else {
                htmlParser = parser.query(selector);
            }
            Object link;
            if (!StringUtils.isEmpty(rule.getMethod())) {
                try {
                    Method method = htmlParser.getClass().getMethod(rule.getMethod());
                    Object result = method.invoke(htmlParser);
                    link = result;
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                    link = null;
                }
            } else {
                link = htmlParser.absUrl(rule.getAttr());
            }
            if (link != null) {
                if (rule.isArray()) {
                    List<String> links = (List<String>) link;
                    for (String _link : links) {
                        Task task;
                        if (StringUtils.isNotEmpty(rule.getNextTask())) {
                            task = Config.newTask(rule.getNextTask());

                        } else {
                            task = new Task();
                        }
                        task.setUrl(_link);
                        flowData.addNextTaskInfo(task);
                    }
                } else {
                    Task task;
                    if (StringUtils.isNotEmpty(rule.getNextTask())) {
                        task = Config.newTask(rule.getNextTask());
                    } else {
                        task = new Task();
                    }
                    task.setUrl((String) link);
                    flowData.addNextTaskInfo(task);
                }
            }
        }
    }
}
